
<?php

/*
   Threads.php

   -- Interacts with Threads data in database.
   -- Assumes an open connection in the calling page.
   -- Assumes all lisp-tree representations of threads are properly formatted.

   -- Methods:

   getInitialThreadTree($fileno, $annotator)
      -- Fills the roots[], parents[], and children[] arrays as one JSON
         using all the threads annotated by $annotator in $fileno
      -- Returns a JSON of the following form:
         { "roots"    : [      root1, root2, ... , rootn        ],
           "parents"  : {   <post_num> : <parent_of_post_num>   },
           "children" : {   <post_num> : [child1, ..., childn]  }
         }
      -- uses helper function _updateInitialThreadTree

   getLispTree($fileno, $annotator, $thread)
      -- Retrieves the lisp-tree from the Threads db table based on
         $thread made in $fileno by $annotator
      -- Output is a single string with the lisp-tree representation

   makeLispTree(&$childrenArray, $rootPostNum)
      -- Without db interaction, parses the children[] arrays to construct
         the lisp-tree representation of the thread starting at $rootPostNum
      -- Does not edit either parentsArray nor childrenArray
      -- Outputs a single string list-tree representation of the
         thread starting at $rootPostNum
      -- Uses helper function _preOrderThreadTraversal

   getRoot(&$parentsArray, $childPostNum)
      -- Without db interaction, traverses the parents array upward from
         $childPostNum to find $childPostNum's root node
      -- Outputs the root node number 
         or "-1" if $childPostNum is a key in the parents array

   getNodesInThreadTree(&$childrenArray, $rootPostNum)
      -- Without db interaction, traverses the children of the Thread Tree
         rooted at $rootPostNum and collects all the nodes in that tree.
      -- Outputs a flat array with all the nodes in the tree.
      -- Uses helper function _preOrderNodeRetrieval

*/


require_once('db_config.php');


function getInitialThreadTree($fileno, $annotator)
{  $root = '';
   $initArray = array();
   $initArray["roots"] = array();
   $initArray["parents"] = array();
   $initArray["children"] = array();
   $threadsTable = $GLOBALS['threadsTable'];
   $threads = mysql_query("SELECT thread, tree
                           FROM $threadsTable
                           WHERE filenumber = $fileno
                              AND annotator = $annotator
                           ORDER BY thread ASC")
              or die(__FILE__ . ":" . __LINE__ .
                     ": Couldn't execute thread query." . mysql_error());
   while($row = mysql_fetch_array($threads, MYSQL_ASSOC))
   { $root = $row["thread"];
     array_push($initArray["roots"], $root);
     _updateInitialThreadTree($initArray["parents"], $initArray["children"], 
                              $row["tree"]);
   }
   $initArray["roots"] = json_encode($initArray["roots"]);
   $initArray["parents"] = json_encode($initArray["parents"]);
   $initArray["children"] = json_encode($initArray["children"]);
   $initJSON = json_encode($initArray);
   return $initJSON;
}

function _updateInitialThreadTree(&$parentsArray, &$childrenArray, $lisptree)
{  $len = strlen($lisptree);
   $moveDown = false;
   $currParent = "-1";
   $currPost = "";
   $currPostUpdated = true;
   for($i = 0; $i < $len; $i++)
   {  $char = $lisptree[$i];
      switch($char)
      {  case " ":  
            if($moveDown)
            {  $moveDown = false;
               $parentsArray["$currPost"] = $currParent;
               if($currParent != "-1")
               {  array_push($childrenArray["$currParent"], $currPost); }
               $childrenArray["$currPost"] = array();
               $currParent = $currPost;
               $currPost = "";
            }
            elseif($currPostUpdated == false)
            {  $currPostUpdated = true;
               $parentsArray["$currPost"] = $currParent;
               array_push($childrenArray["$currParent"], $currPost);
               $childrenArray["$currPost"] = array();
               $currPost = "";
            }
            break;
         case "(":  $moveDown = true; break;
         case ")":  
            if($currPostUpdated == false)
            {  $currPostUpdated = true;
               $parentsArray["$currPost"] = $currParent;
               if($moveDown == false)
               { array_push($childrenArray["$currParent"], $currPost); }
               $childrenArray["$currPost"] = array();
               $currPost = "";
            }
            $currParent = $parentsArray["$currParent"];
            break;
         default:   $currPost .= $char; $currPostUpdated = false; break;
      }
   }
}

function getLispTree($fileno, $annotator, $thread)
{  $threadsTable = $GLOBALS['threadsTable'];
   $tree = mysql_query("SELECT tree
                           FROM $threadsTable
                           WHERE filenumber = $fileno
                              AND annotator = $annotator
                              AND thread = $thread")
              or die(__FILE__ . ":" . __LINE__ .
                     ": Couldn't execute thread query." . mysql_error());
   $row = mysql_fetch_assoc($tree)
       or die(__FILE__ . ":" . __LINE__ .
                     ": lisptree query returned no results." . mysql_error());
   $lisptree = $row['tree'];
   return $lisptree;
}

function makeLispTree(&$childrenArray, $rootPostNum)
{  $lisptree = '';
   if(array_key_exists($rootPostNum, $childrenArray) == false)
   {  die(__FILE__ . ":" . __LINE__ . 
          ": $rootPostNum is not the root of a (sub)Thread.");
   }
   _preOrderThreadTraversal($childrenArray, $rootPostNum, $lisptree);
   $lisptree = rtrim($lisptree);
   $lisptree = preg_replace('/\) \s*\)/', '))', $lisptree);
   $lisptree = preg_replace('/(\d) \s*\)/', '$1)', $lisptree);
   return $lisptree;
}

function _preOrderThreadTraversal(&$childrenArray, $subRoot, &$lispTree)
{  $lispTree .= "($subRoot ";
   $childArray = $childrenArray["$subRoot"];
   reset($childArray);
   while(list($key,$val) = each($childArray))
   {  if(empty($childrenArray["$val"]))  $lispTree .= "$val ";
      else  _preOrderThreadTraversal($childrenArray, $val, $lispTree);
   }
   $lispTree .= ") ";
}

function getRoot(&$parentsArray, $childPostNum)
{  if(array_key_exists($childPostNum, $parentsArray) == false)
   { return "-1"; }
   $prevParent = $childPostNum;
   $parent = '';
   while(($parent = $parentsArray["$prevParent"]) != "-1")
   { $prevParent = $parent; }
   return $prevParent;
}

function getNodesInThreadTree(&$childrenArray, $rootPostNum)
{  $nodeArray = array();
   if(array_key_exists($rootPostNum, $childrenArray) == false)
   {  return $nodeArray;  }
   _preOrderNodeRetrieval($childrenArray, $rootPostNum, $nodeArray);
   return $nodeArray;
}

function _preOrderNodeRetrieval(&$childrenArray, $subRoot, &$nodeArray)
{  array_push($nodeArray, $subRoot);
   $childArray = $childrenArray["$subRoot"];
   reset($childArray);
   while(list($key,$val) = each($childArray))
   {  if(empty($childrenArray["$val"]) == false)
      {  _preOrderNodeRetrieval($childrenArray, $val, $nodeArray);  }
   }
}

?>

